#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
TCP数据服务

实现基于HTTP TCP请求的数据传输服务。
提供数据上传、实时数据获取、版本控制等功能。
"""

import time
import asyncio
from datetime import datetime, timezone
from typing import Dict, List, Optional, Any
import logging
import json
from dataclasses import dataclass
from pydantic import BaseModel, Field, validator

from .memory_cache_service import get_memory_cache, MemoryCacheService
from .sleep_monitoring_service import SleepMonitoringService
from models.sleep_monitoring import SleepMonitoringRecord

logger = logging.getLogger(__name__)


# Pydantic模型定义
class BrainwaveRatios(BaseModel):
    """脑波比例数据"""
    delta: float = Field(..., ge=0, le=1, description="Delta波比例")
    theta: float = Field(..., ge=0, le=1, description="Theta波比例")
    alpha: float = Field(..., ge=0, le=1, description="Alpha波比例")
    beta: float = Field(..., ge=0, le=1, description="Beta波比例")
    gamma: float = Field(..., ge=0, le=1, description="Gamma波比例")
    
    @validator('*', pre=True)
    def validate_ratios(cls, v):
        if not isinstance(v, (int, float)):
            raise ValueError('脑波比例必须是数字')
        return float(v)


class RawChannels(BaseModel):
    """原始通道数据"""
    channel_1: List[float] = Field(..., description="通道1数据")
    channel_2: List[float] = Field(..., description="通道2数据")
    channel_3: List[float] = Field(..., description="通道3数据")
    channel_4: List[float] = Field(..., description="通道4数据")
    channel_5: List[float] = Field(..., description="通道5数据")
    channel_6: List[float] = Field(..., description="通道6数据")
    channel_7: List[float] = Field(..., description="通道7数据")
    channel_8: List[float] = Field(..., description="通道8数据")


class EEGData(BaseModel):
    """EEG数据内容"""
    state: str = Field(..., description="睡眠状态")
    confidence: float = Field(..., ge=0, le=1, description="置信度")
    brainwave_ratios: BrainwaveRatios = Field(..., description="脑波比例")
    raw_channels: RawChannels = Field(..., description="原始通道数据")
    signal_quality: float = Field(..., ge=0, le=1, description="信号质量")
    battery_level: int = Field(..., ge=0, le=100, description="电池电量")


class EEGDataRequest(BaseModel):
    """EEG数据上传请求"""
    room_id: str = Field(..., min_length=1, max_length=50, description="房间ID")
    session_id: str = Field(..., min_length=1, max_length=100, description="会话ID")
    timestamp: str = Field(..., description="时间戳(ISO格式)")
    sequence: int = Field(..., ge=1, description="序列号")
    data: EEGData = Field(..., description="EEG数据")
    
    @validator('timestamp')
    def validate_timestamp(cls, v):
        try:
            datetime.fromisoformat(v.replace('Z', '+00:00'))
            return v
        except ValueError:
            raise ValueError('时间戳格式无效，请使用ISO格式')


class EEGDataResponse(BaseModel):
    """EEG数据响应"""
    status: str = Field(default="success", description="状态")
    timestamp: str = Field(..., description="服务器时间戳")
    version: int = Field(..., description="数据版本号")
    message: Optional[str] = Field(None, description="消息")


class RealtimeDataResponse(BaseModel):
    """实时数据响应"""
    room_id: str = Field(..., description="房间ID")
    version: int = Field(..., description="当前版本号")
    last_update: str = Field(..., description="最后更新时间")
    data: Dict[str, Any] = Field(..., description="数据内容")


class VersionCheckResponse(BaseModel):
    """版本检查响应"""
    room_id: str = Field(..., description="房间ID")
    version: int = Field(..., description="当前版本号")
    last_update: str = Field(..., description="最后更新时间")
    has_new_data: bool = Field(..., description="是否有新数据")


@dataclass
class ServiceMetrics:
    """服务性能指标"""
    upload_count: int = 0
    query_count: int = 0
    error_count: int = 0
    avg_upload_time: float = 0.0
    avg_query_time: float = 0.0
    start_time: float = 0.0


class TCPDataService:
    """TCP数据服务
    
    提供基于HTTP TCP的数据传输服务，包括：
    - 数据上传处理
    - 实时数据获取
    - 版本控制
    - 数据存储
    - 性能监控
    """
    
    def __init__(self, 
                 memory_cache: Optional[MemoryCacheService] = None,
                 sleep_service: Optional[SleepMonitoringService] = None):
        """
        初始化TCP数据服务
        
        Args:
            memory_cache: 内存缓存服务实例
            sleep_service: 睡眠监控服务实例
        """
        self.memory_cache = memory_cache or get_memory_cache()
        self.sleep_service = sleep_service or SleepMonitoringService()
        
        # 性能指标
        self.metrics = ServiceMetrics(start_time=time.time())
        
        # 数据验证配置
        self.valid_states = {'awake', 'light_sleep', 'deep_sleep', 'rem_sleep'}
        self.max_sequence_gap = 1000  # 最大序列号间隔
        
        logger.info("TCP数据服务已启动")
    
    async def upload_eeg_data(self, request: EEGDataRequest) -> EEGDataResponse:
        """上传EEG数据
        
        Args:
            request: EEG数据上传请求
            
        Returns:
            上传响应
            
        Raises:
            ValueError: 数据验证失败
            Exception: 存储失败
        """
        start_time = time.time()
        
        try:
            # 数据验证
            self._validate_eeg_data(request)
            
            # 转换为存储格式
            storage_data = self._convert_to_storage_format(request)
            
            # 存储到数据库
            success = await self._store_to_database(storage_data)
            if not success:
                raise Exception("数据库存储失败")
            
            # 更新内存缓存
            cache_result = self.memory_cache.add_data(request.room_id, storage_data)
            
            # 更新指标
            self.metrics.upload_count += 1
            upload_time = time.time() - start_time
            self._update_avg_upload_time(upload_time)
            
            logger.info(f"EEG数据上传成功 - 房间: {request.room_id}, 版本: {cache_result['version']}, 耗时: {upload_time:.3f}s")
            
            return EEGDataResponse(
                status="success",
                timestamp=datetime.now(timezone.utc).isoformat(),
                version=cache_result['version'],
                message=f"数据已成功存储，当前版本: {cache_result['version']}"
            )
            
        except ValueError as e:
            self.metrics.error_count += 1
            logger.warning(f"数据验证失败 - 房间: {request.room_id}, 错误: {e}")
            raise
        except Exception as e:
            self.metrics.error_count += 1
            logger.error(f"数据上传失败 - 房间: {request.room_id}, 错误: {e}")
            raise
    
    async def get_realtime_data(self, 
                              room_id: str, 
                              since: Optional[float] = None,
                              limit: Optional[int] = None) -> RealtimeDataResponse:
        """获取实时数据
        
        Args:
            room_id: 房间ID
            since: 起始时间戳
            limit: 最大返回条数
            
        Returns:
            实时数据响应
        """
        start_time = time.time()
        
        try:
            # 获取最新数据
            latest_data = self.memory_cache.get_latest_data(room_id)
            
            # 获取时间窗口数据
            recent_data = []
            if since is not None:
                recent_data = self.memory_cache.get_data_since_timestamp(
                    room_id, since, limit
                )
            
            # 获取版本信息
            version = self.memory_cache.get_version(room_id)
            
            # 更新指标
            self.metrics.query_count += 1
            query_time = time.time() - start_time
            self._update_avg_query_time(query_time)
            
            logger.debug(f"实时数据查询完成 - 房间: {room_id}, 版本: {version}, 最新数据: {latest_data is not None}, 历史数据: {len(recent_data)}条")
            
            return RealtimeDataResponse(
                room_id=room_id,
                version=version,
                last_update=datetime.now(timezone.utc).isoformat(),
                data={
                    'latest': latest_data,
                    'recent': recent_data,
                    'count': len(recent_data)
                }
            )
            
        except Exception as e:
            self.metrics.error_count += 1
            logger.error(f"实时数据查询失败 - 房间: {room_id}, 错误: {e}")
            raise
    
    async def check_version(self, room_id: str, client_version: Optional[int] = None) -> VersionCheckResponse:
        """检查版本更新
        
        Args:
            room_id: 房间ID
            client_version: 客户端版本号
            
        Returns:
            版本检查响应
        """
        try:
            current_version = self.memory_cache.get_version(room_id)
            has_new_data = self.memory_cache.get_latest_data(room_id) is not None
            
            # 如果提供了客户端版本，检查是否有更新
            if client_version is not None:
                has_new_data = self.memory_cache.check_version_update(room_id, client_version)
            
            logger.debug(f"版本检查完成 - 房间: {room_id}, 当前版本: {current_version}, 客户端版本: {client_version}, 有新数据: {has_new_data}")
            
            return VersionCheckResponse(
                room_id=room_id,
                version=current_version,
                last_update=datetime.now(timezone.utc).isoformat(),
                has_new_data=has_new_data
            )
            
        except Exception as e:
            self.metrics.error_count += 1
            logger.error(f"版本检查失败 - 房间: {room_id}, 错误: {e}")
            raise
    
    async def get_room_status(self, room_id: str) -> Dict[str, Any]:
        """获取房间状态信息
        
        Args:
            room_id: 房间ID
            
        Returns:
            房间状态信息
        """
        try:
            room_info = self.memory_cache.get_room_info(room_id)
            
            # 获取数据库中的会话信息
            db_sessions = await self.sleep_service.get_active_sessions_by_room(room_id)
            
            return {
                **room_info,
                'active_sessions': len(db_sessions),
                'service_uptime': time.time() - self.metrics.start_time
            }
            
        except Exception as e:
            logger.error(f"获取房间状态失败 - 房间: {room_id}, 错误: {e}")
            raise
    
    def get_service_metrics(self) -> Dict[str, Any]:
        """获取服务性能指标
        
        Returns:
            性能指标字典
        """
        uptime = time.time() - self.metrics.start_time
        
        return {
            'uptime_seconds': uptime,
            'upload_count': self.metrics.upload_count,
            'query_count': self.metrics.query_count,
            'error_count': self.metrics.error_count,
            'avg_upload_time': self.metrics.avg_upload_time,
            'avg_query_time': self.metrics.avg_query_time,
            'upload_rate': self.metrics.upload_count / uptime if uptime > 0 else 0,
            'query_rate': self.metrics.query_count / uptime if uptime > 0 else 0,
            'error_rate': self.metrics.error_count / (self.metrics.upload_count + self.metrics.query_count) if (self.metrics.upload_count + self.metrics.query_count) > 0 else 0,
            'cache_stats': self.memory_cache.get_cache_stats()
        }
    
    def _validate_eeg_data(self, request: EEGDataRequest) -> None:
        """验证EEG数据
        
        Args:
            request: EEG数据请求
            
        Raises:
            ValueError: 验证失败
        """
        # 验证睡眠状态
        if request.data.state not in self.valid_states:
            raise ValueError(f"无效的睡眠状态: {request.data.state}")
        
        # 验证脑波比例总和
        ratios = request.data.brainwave_ratios
        total_ratio = ratios.delta + ratios.theta + ratios.alpha + ratios.beta + ratios.gamma
        if not (0.8 <= total_ratio <= 1.2):  # 允许一定误差
            raise ValueError(f"脑波比例总和异常: {total_ratio}")
        
        # 验证通道数据长度
        channels = request.data.raw_channels
        channel_lengths = [
            len(channels.channel_1), len(channels.channel_2),
            len(channels.channel_3), len(channels.channel_4),
            len(channels.channel_5), len(channels.channel_6),
            len(channels.channel_7), len(channels.channel_8)
        ]
        
        if not all(length > 0 for length in channel_lengths):
            raise ValueError("所有通道都必须包含数据")
        
        if len(set(channel_lengths)) > 1:
            raise ValueError("所有通道的数据长度必须相同")
        
        # 验证数据范围
        if not (0 <= request.data.confidence <= 1):
            raise ValueError(f"置信度超出范围: {request.data.confidence}")
        
        if not (0 <= request.data.signal_quality <= 1):
            raise ValueError(f"信号质量超出范围: {request.data.signal_quality}")
        
        if not (0 <= request.data.battery_level <= 100):
            raise ValueError(f"电池电量超出范围: {request.data.battery_level}")
    
    def _convert_to_storage_format(self, request: EEGDataRequest) -> Dict[str, Any]:
        """转换为存储格式
        
        Args:
            request: EEG数据请求
            
        Returns:
            存储格式的数据
        """
        return {
            'room_id': request.room_id,
            'session_id': request.session_id,
            'timestamp': request.timestamp,
            'sequence': request.sequence,
            'state': request.data.state,
            'confidence': request.data.confidence,
            'brainwave_ratios': request.data.brainwave_ratios.dict(),
            'raw_channels': request.data.raw_channels.dict(),
            'signal_quality': request.data.signal_quality,
            'battery_level': request.data.battery_level,
            'processed_at': datetime.now(timezone.utc).isoformat()
        }
    
    async def _store_to_database(self, data: Dict[str, Any]) -> bool:
        """存储数据到数据库
        
        Args:
            data: 要存储的数据
            
        Returns:
            是否成功存储
        """
        try:
            timestamp = datetime.fromisoformat(data['timestamp'].replace('Z', '+00:00'))
            timestamp_ms = int(timestamp.timestamp() * 1000)
            
            # 首先尝试获取现有的会话记录
            existing_session = await self.sleep_service.get_session_by_id(data['session_id'])
            
            if existing_session:
                # 更新现有会话记录
                record = existing_session
                
                # 确保start_time也是timezone-aware的
                if record.start_time.tzinfo is None:
                    record.start_time = record.start_time.replace(tzinfo=timezone.utc)
                
                # 更新会话的结束时间和总时长
                record.end_time = timestamp
                record.total_seconds = int((timestamp - record.start_time).total_seconds())
                
                # 追加脑波比例数据
                ratios = data['brainwave_ratios']
                self._append_brainwave_data(record, timestamp_ms, ratios)
                
                # 追加原始通道数据
                channels = data['raw_channels']
                self._append_channel_data(record, timestamp_ms, channels)
                
                # 追加其他数据
                self._append_other_data(record, timestamp_ms, data)
                
                # 动态更新主导状态和平均置信度
                self._update_session_summary(record, data['state'], data['confidence'])
                
                logger.debug(f"更新现有会话记录 - 会话: {data['session_id']}, 序列: {data['sequence']}")
                
            else:
                # 创建新的会话记录
                record = SleepMonitoringRecord(
                    room_id=data['room_id'],
                    session_id=data['session_id'],
                    start_time=timestamp,
                    end_time=timestamp,
                    total_seconds=1,
                    dominant_state=data['state'],
                    avg_confidence=data['confidence']
                )
                
                # 设置初始数据
                ratios = data['brainwave_ratios']
                self._set_initial_brainwave_data(record, timestamp_ms, ratios)
                
                channels = data['raw_channels']
                self._set_initial_channel_data(record, timestamp_ms, channels)
                
                self._set_initial_other_data(record, timestamp_ms, data)
                
                logger.debug(f"创建新会话记录 - 会话: {data['session_id']}, 序列: {data['sequence']}")
            
            # 保存到数据库
            record.save()
            return True
            
        except Exception as e:
            logger.error(f"数据库存储失败: {e}")
            return False
    
    def _append_brainwave_data(self, record: SleepMonitoringRecord, timestamp_ms: int, ratios: Dict[str, float]):
        """追加脑波比例数据到现有记录"""
        # 获取现有数据并追加新数据点
        delta_data = record.get_delta_ratio_data() or []
        delta_data.append([timestamp_ms, ratios['delta']])
        record.set_delta_ratio_data(delta_data)
        
        theta_data = record.get_theta_ratio_data() or []
        theta_data.append([timestamp_ms, ratios['theta']])
        record.set_theta_ratio_data(theta_data)
        
        alpha_data = record.get_alpha_ratio_data() or []
        alpha_data.append([timestamp_ms, ratios['alpha']])
        record.set_alpha_ratio_data(alpha_data)
        
        beta_data = record.get_beta_ratio_data() or []
        beta_data.append([timestamp_ms, ratios['beta']])
        record.set_beta_ratio_data(beta_data)
        
        gamma_data = record.get_gamma_ratio_data() or []
        gamma_data.append([timestamp_ms, ratios['gamma']])
        record.set_gamma_ratio_data(gamma_data)
    
    def _append_channel_data(self, record: SleepMonitoringRecord, timestamp_ms: int, channels: Dict[str, List[float]]):
        """追加原始通道数据到现有记录"""
        for i in range(1, 9):
            channel_key = f'channel_{i}'
            if channel_key in channels:
                existing_data = record.get_raw_channel_data(i) or []
                existing_data.append([timestamp_ms, channels[channel_key]])
                record.set_raw_channel_data(i, existing_data)
    
    def _append_other_data(self, record: SleepMonitoringRecord, timestamp_ms: int, data: Dict[str, Any]):
        """追加其他数据到现有记录"""
        # 信号质量数据
        quality_data = record.get_signal_quality_data() or []
        quality_data.append([timestamp_ms, data['signal_quality']])
        record.set_signal_quality_data(quality_data)
        
        # 电池电量数据
        battery_data = record.get_battery_level_data() or []
        battery_data.append([timestamp_ms, data['battery_level']])
        record.set_battery_level_data(battery_data)
        
        # 状态数据
        states_data = record.get_states_data() or []
        states_data.append([timestamp_ms, data['state']])
        record.set_states_data(states_data)
        
        # 置信度数据
        confidence_data = record.get_confidence_data() or []
        confidence_data.append([timestamp_ms, data['confidence']])
        record.set_confidence_data(confidence_data)
    
    def _set_initial_brainwave_data(self, record: SleepMonitoringRecord, timestamp_ms: int, ratios: Dict[str, float]):
        """设置初始脑波比例数据"""
        record.set_delta_ratio_data([[timestamp_ms, ratios['delta']]])
        record.set_theta_ratio_data([[timestamp_ms, ratios['theta']]])
        record.set_alpha_ratio_data([[timestamp_ms, ratios['alpha']]])
        record.set_beta_ratio_data([[timestamp_ms, ratios['beta']]])
        record.set_gamma_ratio_data([[timestamp_ms, ratios['gamma']]])
    
    def _set_initial_channel_data(self, record: SleepMonitoringRecord, timestamp_ms: int, channels: Dict[str, List[float]]):
        """设置初始原始通道数据"""
        for i in range(1, 9):
            channel_key = f'channel_{i}'
            if channel_key in channels:
                record.set_raw_channel_data(i, [[timestamp_ms, channels[channel_key]]])
    
    def _set_initial_other_data(self, record: SleepMonitoringRecord, timestamp_ms: int, data: Dict[str, Any]):
        """设置初始其他数据"""
        record.set_signal_quality_data([[timestamp_ms, data['signal_quality']]])
        record.set_battery_level_data([[timestamp_ms, data['battery_level']]])
        record.set_states_data([[timestamp_ms, data['state']]])
        record.set_confidence_data([[timestamp_ms, data['confidence']]])
    
    def _update_session_summary(self, record: SleepMonitoringRecord, current_state: str, current_confidence: float):
        """动态更新会话摘要信息"""
        # 获取所有状态数据来计算主导状态
        states_data = record.get_states_data() or []
        if states_data:
            # 统计各状态出现次数
            state_counts = {}
            confidence_sum = 0
            for _, state in states_data:
                state_counts[state] = state_counts.get(state, 0) + 1
            
            # 获取所有置信度数据来计算平均值
            confidence_data = record.get_confidence_data() or []
            if confidence_data:
                confidence_sum = sum(conf for _, conf in confidence_data)
                record.avg_confidence = confidence_sum / len(confidence_data)
            
            # 更新主导状态（出现次数最多的状态）
            if state_counts:
                record.dominant_state = max(state_counts, key=state_counts.get)
    
    def _update_avg_upload_time(self, upload_time: float) -> None:
        """更新平均上传时间"""
        if self.metrics.upload_count == 1:
            self.metrics.avg_upload_time = upload_time
        else:
            # 使用指数移动平均
            alpha = 0.1
            self.metrics.avg_upload_time = (
                alpha * upload_time + 
                (1 - alpha) * self.metrics.avg_upload_time
            )
    
    def _update_avg_query_time(self, query_time: float) -> None:
        """更新平均查询时间"""
        if self.metrics.query_count == 1:
            self.metrics.avg_query_time = query_time
        else:
            # 使用指数移动平均
            alpha = 0.1
            self.metrics.avg_query_time = (
                alpha * query_time + 
                (1 - alpha) * self.metrics.avg_query_time
            )
    
    def shutdown(self) -> None:
        """关闭服务"""
        logger.info(f"TCP数据服务关闭 - 处理了 {self.metrics.upload_count} 次上传, {self.metrics.query_count} 次查询")


# 全局服务实例
_global_tcp_service: Optional[TCPDataService] = None
_service_lock = asyncio.Lock()


async def get_tcp_data_service() -> TCPDataService:
    """获取全局TCP数据服务实例（单例模式）
    
    Returns:
        TCP数据服务实例
    """
    global _global_tcp_service
    
    if _global_tcp_service is None:
        async with _service_lock:
            if _global_tcp_service is None:
                _global_tcp_service = TCPDataService()
    
    return _global_tcp_service


def shutdown_tcp_data_service() -> None:
    """关闭全局TCP数据服务实例"""
    global _global_tcp_service
    
    if _global_tcp_service is not None:
        _global_tcp_service.shutdown()
        _global_tcp_service = None